package com.hzw.saas.service.product.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.product.ILicenseProductService;
import com.hzw.saas.api.product.ILicenseUserService;
import com.hzw.saas.api.product.IProductService;
import com.hzw.saas.api.product.dto.*;
import com.hzw.saas.api.property.IPropertyService;
import com.hzw.saas.api.property.enmus.SysDictKeyEnum;
import com.hzw.saas.api.property.enmus.SysDictModuleEnum;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.config.util.PageParam;
import com.hzw.saas.common.util.MapperUtil;
import com.hzw.saas.common.util.ObjFieldUtil;
import com.hzw.saas.common.util.enums.AssertEnum;
import com.hzw.saas.service.product.mapper.LicenseUserMapper;
import com.hzw.saas.service.product.model.LicenseUser;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

/**
 * <p>
 *
 * </p>
 *
 * @author sonam
 * @since 2021/4/8 13:35
 */
@RequiredArgsConstructor
@Service("licenseUserServiceImpl")
public class LicenseUserServiceImpl extends ServiceImpl<LicenseUserMapper, LicenseUser> implements ILicenseUserService, IService<LicenseUser> {

    @Resource(name = IPropertyService.SYS_DICT_BEAN)
    private IPropertyService<SysDictKeyEnum> propertyService;

    @Resource
    private ILicenseProductService iLicenseProductService;
    @Resource
    private IProductService productService;

    @Override
    public List<LicenseUserBO> getLicenseUser(String userId, String productId, AssertEnum assertEnum) {
        LambdaQueryChainWrapper<LicenseUser> query = super.lambdaQuery()
            .eq(LicenseUser::getUserId, userId).eq(LicenseUser::getProductId, productId);
        List<LicenseUser> licenseUser = query.list();
        AssertEnum.assertResult(assertEnum, licenseUser, "用户对应的产品权限");
        return MapperUtil.nf().mapAsList(licenseUser, LicenseUserBO.class);
    }

    @Override
    public List<UserProductAuthDto> listProducts(String userId, Integer... cloudType) {
        IPage<ProductDto> productsPage = productService.getProductsByCloudTypes(new PageParam(false), cloudType);
        List<ProductDto> products = productsPage.getRecords();
        List<LicenseUser> licenseUserList = super.lambdaQuery()
            .eq(LicenseUser::getUserId, userId)
            .ge(LicenseUser::getValidatedExpiredDate, new Date())
            .list();

        List<UserProductAuthDto> result = new ArrayList<>();
        for (ProductDto product : products) {
            UserProductAuthDto resultEntity = MapperUtil.nf().map(product, UserProductAuthDto.class);
            resultEntity.setLicense(0);
            for (LicenseUser licenseUser : licenseUserList) {
                if (Objects.equals(product.getProdId(), licenseUser.getProductId())) {
                    resultEntity.setLicenseExpireDate(licenseUser.getValidatedExpiredDate());
                    resultEntity.setMaxCpuCore(licenseUser.getMaxCpuCore());
                    resultEntity.setMaxMemory(licenseUser.getMaxMemory());
                    resultEntity.setParallelModel(licenseUser.getParallelModel());
                    resultEntity.setProductType(licenseUser.getProductType());
                    resultEntity.setLicense(1);
                    licenseUserList.remove(licenseUser);
                    break;
                }
            }
            result.add(resultEntity);
        }
        return result;
    }

    @Override
    public List<UserProductInfoDto> listUserProducts(String userId, Integer... cloudType) {
        if (StrUtil.isBlank(userId))
            return new ArrayList<>();
        List<Integer> cloudTypeList = Objects.isNull(cloudType) ? new ArrayList<>() : Arrays.asList(cloudType);
        List<LicenseUser> licenseUserList = this.lambdaQuery()
            .eq(LicenseUser::getUserId, userId)
            .ge(LicenseUser::getValidatedExpiredDate, new Date())
            .list();
        List<UserProductInfoDto> productList = new ArrayList<>();
        for (LicenseUser licenseUser : licenseUserList) {
            ProductDto product = productService.getProductById(licenseUser.getProductId());
            if (Objects.isNull(product))
                continue;
            if (!cloudTypeList.isEmpty() && !cloudTypeList.contains(product.getCloudType()))
                continue;
            UserProductInfoDto userProduct = MapperUtil.nf().map(product, UserProductInfoDto.class);
            userProduct.setLicenseId(licenseUser.getLicenseId());
            userProduct.setLicenseExpireDate(licenseUser.getValidatedExpiredDate());
            userProduct.setMaxCpuCore(licenseUser.getMaxCpuCore());
            userProduct.setMaxMemory(licenseUser.getMaxMemory());
            userProduct.setParallelModel(licenseUser.getParallelModel());
            userProduct.setProductType(licenseUser.getProductType());
            String parallelModelText = propertyService.getPropertyValue(SysDictModuleEnum.PRODUCT_PARALLEL_MODEL.getModule(),
                String.valueOf(licenseUser.getParallelModel()));
            userProduct.setParallelModelText(parallelModelText);
            productList.add(userProduct);
        }
        return productList;
    }

    @Override
    public List<LicenseUserBO> searchLicenseUser(LicenseUserBO licenseUserBO) {
        ObjFieldUtil.isAllNullFields(licenseUserBO, ObjFieldUtil.ConvertNull.BLANK);
        LicenseUser licenseUser = MapperUtil.nf().map(licenseUserBO, LicenseUser.class);
        List<LicenseUser> list = this.list(Wrappers.<LicenseUser>query().setEntity(licenseUser));
        return MapperUtil.nf().mapAsList(list, LicenseUserBO.class);
    }

    @Override
    public boolean updateLicenseUser(String userId, LicenseUserBO licenseUserBO) {
        if (Objects.isNull(licenseUserBO))
            return false;
        LicenseUser licenseUser = MapperUtil.nf().map(licenseUserBO, LicenseUser.class);
        this.checkLicenseUser(userId, licenseUser);
        // 删除用户对应产品license有效期信息
        this.lambdaUpdate()
            .eq(LicenseUser::getProductId, licenseUser.getProductId())
            .eq(LicenseUser::getUserId, licenseUser.getUserId()).remove();
        return this.save(licenseUser);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateLicenseUser(String userId, String licenseId) {
        AssertUtil.assertThrow("userId和licenseId不可为空", StrUtil.hasBlank(licenseId, userId));
        LicenseProductBO license = iLicenseProductService.getByLicenseId(licenseId);
        AssertUtil.assertThrow("license不存在:" + licenseId, Objects.isNull(license));
        // 持久化用户license过期数据
        LicenseUser licenseUser = this.convert(userId, license);
        // 删除用户对应产品license有效期信息
        this.lambdaUpdate()
            .eq(LicenseUser::getProductId, license.getProductId())
            .eq(LicenseUser::getUserId, userId).remove();
        return this.save(licenseUser);
    }

    @Override
    public boolean batchUpdateLicenseUser(String userId, List<LicenseUserBO> licenseUserList) {
        if (Objects.isNull(licenseUserList))
            return false;
        List<LicenseUser> entityList = MapperUtil.nf().mapAsList(licenseUserList, LicenseUser.class);
        for (LicenseUser licenseUser : entityList) {
            this.checkLicenseUser(userId, licenseUser);
        }
        // 删除用户license
        this.lambdaUpdate().eq(LicenseUser::getUserId, userId).remove();
        return super.saveBatch(entityList);
    }

    @Override
    public boolean batchUpdateLicenseUser(String userId, String levelId) {
        AssertUtil.assertThrow("userId和levelId不可为空", StrUtil.hasBlank(userId, levelId));
        List<LicenseProductBO> licenseList = iLicenseProductService.listLicenseByLevel(levelId);
        List<LicenseUser> licenseUserList = this.convert(userId, licenseList);
        // 删除用户license
        this.lambdaUpdate().eq(LicenseUser::getUserId, userId).remove();
        return super.saveBatch(licenseUserList);
    }

    private LicenseUser convert(String userId, LicenseProductBO licenseProduct) {
        if (Objects.isNull(licenseProduct))
            return null;
        int validPeriod = Optional.of(licenseProduct).map(LicenseProductBO::getValidPeriod).orElse(0);
        Date now = new Date();
        Date expireDate = DateUtil.offsetMonth(now, validPeriod);
        LicenseUser licenseUser = MapperUtil.nf().map(licenseProduct, LicenseUser.class);
        // FIXME: ZZL@06/01/2021 更新license时，过期时间如何确定
        licenseUser.setUserId(userId)
            .setValidatedEffectiveDate(now)
            .setValidatedExpiredDate(expireDate)
            .setMaintenanceEffectiveDate(now)
            .setMaintenanceExpiredDate(expireDate);
        return licenseUser;
    }

    private List<LicenseUser> convert(String userId, List<LicenseProductBO> licenseProductList) {
        List<LicenseUser> result = new ArrayList<>();
        if (CollectionUtil.isEmpty(licenseProductList))
            return result;
        for (LicenseProductBO licenseProduct : licenseProductList) {
            if (Objects.isNull(licenseProduct))
                continue;
            if (Objects.equals(licenseProduct.getOptionalType(), 1))
                continue;
            LicenseUser licenseUser = this.convert(userId, licenseProduct);
            result.add(licenseUser);
        }
        return result;
    }

    private void checkLicenseUser(String userId, LicenseUser licenseUser) {
        LicenseProductBO licenseProduct = this.iLicenseProductService.getByLicenseId(licenseUser.getLicenseId());
        if (Objects.isNull(licenseProduct))
            return;
        MapperUtil.nf().map(licenseUser, licenseProduct);
        MapperUtil.nf().map(licenseProduct, licenseUser);
        licenseUser.setUserId(userId);
        licenseUser.setProductId(licenseProduct.getProductId());
        Date now = new Date();
        int validPeriod = Optional.of(licenseProduct).map(LicenseProductBO::getValidPeriod).orElse(0);
        if (Objects.isNull(licenseUser.getValidatedEffectiveDate()))
            licenseUser.setValidatedEffectiveDate(now);
        if (Objects.isNull(licenseUser.getValidatedExpiredDate()))
            licenseUser.setValidatedExpiredDate(DateUtil.offsetMonth(licenseUser.getValidatedEffectiveDate(), validPeriod));
        if (Objects.isNull(licenseUser.getMaintenanceEffectiveDate()))
            licenseUser.setMaintenanceEffectiveDate(licenseUser.getValidatedEffectiveDate());
        if (Objects.isNull(licenseUser.getMaintenanceExpiredDate()))
            licenseUser.setMaintenanceExpiredDate(licenseUser.getValidatedExpiredDate());
    }
}
